#pragma once

#include <iostream>
#include <memory>
#include <functional>
#include <sys/wait.h>
#include "Socket.hpp"


//我觉得吧，我写这些代码我肯定是不可能一次性把所有的给写完，但是我可以做一个平替，就是遮住部分代码替换成自己的
//先是宏观的，每份文件的目的是做什么
//再是微观的，这份代码具体的接口，内部的细节
//比如TcpServer的功能就是负责服务器和客户端的连接，IO信息交互(IO信息交互的实现主要是http服务，http服务的制定在更上层)
//具体的功能涉及到Socket的功能，服务器启动进行while循环进行服务器和客户端的连接以及IO交互

namespace TcpServerModule
{
    using namespace SocketModule;
    using namespace LogModule;
    using tcphandler_t = std::function<bool(SockPtr, InetAddr)>;//  using SockPtr = std::shared_ptr<Socket>;

   //  是它只负责进行IO，流式的IO，不对协议进行任何处理
    class TcpServer
    {
    public:
        TcpServer(int port)
            : _listensockp(std::make_unique<TcpSocket>()),
              _running(false),
              _port(port)
        {
        }
        void InitServer(tcphandler_t handler)//接受一个tcphandler_t类型的参数，对服务器handler进行初始化
        {
            _handler = handler;
            _listensockp->BuildTcpSocketMethod(_port);
        }
        void Loop()
        {
            _running = true;
            while (_running)
            {
                // 1. Accept
                InetAddr clientaddr;
                auto sockfd = _listensockp->Accepter(&clientaddr);
                if (sockfd == nullptr)
                    continue;
                // 2. IO处理
                LOG(LogLevel::DEBUG) << "get a new client, info is: " << clientaddr.Addr();
                // sockfd->Recv();
                // sockfd->Send();
                pid_t id = fork();
                if (id == 0)
                {
                    //需要关闭_listensockp套接字，因为子进程只进行IO不进行accept连接
                    _listensockp->Close();
                    if (fork() > 0)
                        exit(0);
                    //孙子进程
                    _handler(sockfd, clientaddr);//在这里跳转到http服务，其余的都是Tcp服务器进行IO处理
                    exit(0);
                }
                //爷爷进程
                sockfd->Close();
                waitpid(id, nullptr, 0);//因为在if中直接exit(0)了所以方便的是，不用等待孩子进程完成IO再回收了，而是直接回收孩子进程，让孙子进程进行IO
                //最后由系统来进行回收
            }
            _running = false;
        }
        ~TcpServer()
        {
            _listensockp->Close();
        }

    private:
        // 一定要有一个Listensock
        std::unique_ptr<Socket> _listensockp;//父类的智能指针，能指向子类对象也能指向父类对象
        bool _running;
        tcphandler_t _handler;
        int _port;
    };
}



